import sys
import random
import os
from PyQt6.QtWidgets import (
    QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
    QLabel, QLineEdit, QPushButton, QCheckBox, QSpinBox, QMessageBox,
    QTextEdit, QGroupBox, QProgressBar, QFileDialog, QListWidget, 
    QListWidgetItem, QAbstractItemView
)
from PyQt6.QtCore import Qt, QThread, pyqtSignal


class PasswordGeneratorThread(QThread):
    progress_updated = pyqtSignal(int)
    passwords_generated = pyqtSignal(list)

    def __init__(self, length, count, use_lower, use_upper, use_digits, use_special, 
                 prefix="", suffix="", must_contain=""):
        super().__init__()
        self.length = length
        self.count = count
        self.use_lower = use_lower
        self.use_upper = use_upper
        self.use_digits = use_digits
        self.use_special = use_special
        self.prefix = prefix
        self.suffix = suffix
        self.must_contain = must_contain
        self._is_running = True

    def run(self):
        # 定义字符集
        lower_chars = 'abcdefghijklmnopqrstuvwxyz'
        upper_chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
        digit_chars = '0123456789'
        special_chars = '!@#$%^&*()_+-=[]{}|;:,.<>?'

        # 构建密码字符集
        chars = []
        if self.use_lower:
            chars.extend(list(lower_chars))
        if self.use_upper:
            chars.extend(list(upper_chars))
        if self.use_digits:
            chars.extend(list(digit_chars))
        if self.use_special:
            chars.extend(list(special_chars))

        passwords = []
        
        for i in range(self.count):
            if not self._is_running:
                return
                
            # 确保密码包含至少一个每种选定的字符类型
            password = []
            if self.use_lower:
                password.append(random.choice(lower_chars))
            if self.use_upper:
                password.append(random.choice(upper_chars))
            if self.use_digits:
                password.append(random.choice(digit_chars))
            if self.use_special:
                password.append(random.choice(special_chars))
            
            # 填充剩余长度
            remaining_length = self.length - len(password) - len(self.prefix) - len(self.suffix)
            if remaining_length > 0:
                password.extend(random.choices(chars, k=remaining_length))
            
            # 打乱密码中的字符顺序（不包括前缀和后缀）
            random.shuffle(password)
            
            # 添加前缀和后缀
            password_str = self.prefix + ''.join(password) + self.suffix
            
            # 确保包含指定字符
            if self.must_contain and self.must_contain not in password_str:
                # 如果必须包含的字符不在密码中，替换随机一个字符
                if len(password_str) > 0:
                    index = random.randint(len(self.prefix), len(password_str)-1)
                    password_str = password_str[:index] + self.must_contain + password_str[index+1:]
            
            passwords.append(password_str)
            
            # 更新进度
            progress = int((i + 1) / self.count * 100)
            self.progress_updated.emit(progress)
        
        self.passwords_generated.emit(passwords)
    
    def stop(self):
        self._is_running = False


class PasswordGeneratorApp(QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.setWindowTitle("随机密码生成器")
        self.setGeometry(100, 50, 800, 750)
        
        # 默认保存路径（可修改）
        self.default_save_path = r"C:\Users\Desktop\随机密码生成器\passwords.txt"
        
        self.generator_thread = None
        self.init_ui()
    
    def init_ui(self):
        # 主窗口部件
        main_widget = QWidget()
        self.setCentralWidget(main_widget)
        
        # 主布局
        main_layout = QVBoxLayout()
        main_widget.setLayout(main_layout)
        
        # 设置组
        settings_group = QGroupBox("密码设置")
        settings_layout = QVBoxLayout()
        
        # 密码长度设置
        length_layout = QHBoxLayout()
        length_label = QLabel("密码长度:")
        self.length_spin = QSpinBox()
        self.length_spin.setRange(4, 128)
        self.length_spin.setValue(6)
        length_layout.addWidget(length_label)
        length_layout.addWidget(self.length_spin)
        settings_layout.addLayout(length_layout)
        
        # 生成数量设置
        count_layout = QHBoxLayout()
        count_label = QLabel("生成数量:")
        self.count_spin = QSpinBox()
        self.count_spin.setRange(1, 500)
        self.count_spin.setValue(10)
        count_layout.addWidget(count_label)
        count_layout.addWidget(self.count_spin)
        settings_layout.addLayout(count_layout)
        
        # 字符类型选择
        type_layout = QVBoxLayout()
        type_label = QLabel("包含字符类型:")
        self.digits_check = QCheckBox("数字 (0-9)")
        self.digits_check.setChecked(True)
        self.lower_check = QCheckBox("小写字母 (a-z)")
        self.lower_check.setChecked(True)
        self.upper_check = QCheckBox("大写字母 (A-Z)")
        self.upper_check.setChecked(False)
        self.special_check = QCheckBox("特殊字符 (!@#$%^&*)")
        self.special_check.setChecked(False)
        
        type_layout.addWidget(type_label)
        type_layout.addWidget(self.digits_check)
        type_layout.addWidget(self.lower_check)
        type_layout.addWidget(self.upper_check)
        type_layout.addWidget(self.special_check)
        settings_layout.addLayout(type_layout)
        
        # 前缀、后缀和必须包含字符设置
        custom_layout = QVBoxLayout()
        custom_label = QLabel("自定义字符:")
        
        # 前缀设置
        prefix_layout = QHBoxLayout()
        prefix_label = QLabel("前缀:")
        self.prefix_edit = QLineEdit()
        self.prefix_edit.setPlaceholderText("可选，如: abc")
        prefix_layout.addWidget(prefix_label)
        prefix_layout.addWidget(self.prefix_edit)
        
        # 后缀设置
        suffix_layout = QHBoxLayout()
        suffix_label = QLabel("后缀:")
        self.suffix_edit = QLineEdit()
        self.suffix_edit.setPlaceholderText("可选，如: 123")
        suffix_layout.addWidget(suffix_label)
        suffix_layout.addWidget(self.suffix_edit)
        
        # 必须包含字符设置
        contain_layout = QHBoxLayout()
        contain_label = QLabel("必须包含:")
        self.contain_edit = QLineEdit()
        self.contain_edit.setPlaceholderText("可选，如: @")
        contain_layout.addWidget(contain_label)
        contain_layout.addWidget(self.contain_edit)
        
        custom_layout.addWidget(custom_label)
        custom_layout.addLayout(prefix_layout)
        custom_layout.addLayout(suffix_layout)
        custom_layout.addLayout(contain_layout)
        settings_layout.addLayout(custom_layout)
        
        # 保存路径设置
        path_layout = QHBoxLayout()
        path_label = QLabel("默认保存路径:")
        self.path_edit = QLineEdit(self.default_save_path)
        self.path_edit.setReadOnly(True)
        browse_btn = QPushButton("浏览...")
        browse_btn.clicked.connect(self.browse_save_path)
        path_layout.addWidget(path_label)
        path_layout.addWidget(self.path_edit)
        path_layout.addWidget(browse_btn)
        settings_layout.addLayout(path_layout)
        
        settings_group.setLayout(settings_layout)
        main_layout.addWidget(settings_group)
        
        # 按钮区域
        button_layout = QHBoxLayout()
        self.generate_btn = QPushButton("生成密码")
        self.generate_btn.clicked.connect(self.generate_passwords)
        self.stop_btn = QPushButton("停止生成")
        self.stop_btn.clicked.connect(self.stop_generation)
        self.stop_btn.setEnabled(False)
        self.clear_btn = QPushButton("清空结果")
        self.clear_btn.clicked.connect(self.clear_results)
        button_layout.addWidget(self.generate_btn)
        button_layout.addWidget(self.stop_btn)
        button_layout.addWidget(self.clear_btn)
        main_layout.addLayout(button_layout)
        
        # 进度条
        self.progress_bar = QProgressBar()
        self.progress_bar.setVisible(False)
        main_layout.addWidget(self.progress_bar)
        
        # 结果区域
        result_group = QGroupBox("生成的密码")
        result_layout = QVBoxLayout()
        
        # 密码列表（支持多选）
        self.password_list = QListWidget()
        self.password_list.setSelectionMode(QAbstractItemView.SelectionMode.MultiSelection)
        result_layout.addWidget(self.password_list)
        
        # 操作按钮
        btn_layout = QHBoxLayout()
        self.copy_btn = QPushButton("复制选中密码")
        self.copy_btn.clicked.connect(self.copy_selected_to_clipboard)
        self.copy_all_btn = QPushButton("复制所有密码")
        self.copy_all_btn.clicked.connect(self.copy_all_to_clipboard)
        self.save_btn = QPushButton("保存选中密码")
        self.save_btn.clicked.connect(self.save_selected_to_file)
        self.save_all_btn = QPushButton("保存所有密码")
        self.save_all_btn.clicked.connect(self.save_all_to_file)
        
        btn_layout.addWidget(self.copy_btn)
        btn_layout.addWidget(self.copy_all_btn)
        btn_layout.addWidget(self.save_btn)
        btn_layout.addWidget(self.save_all_btn)
        result_layout.addLayout(btn_layout)
        
        result_group.setLayout(result_layout)
        main_layout.addWidget(result_group)
    
    def browse_save_path(self):
        """浏览并设置默认保存路径"""
        file_path, _ = QFileDialog.getSaveFileName(
            self, "选择默认保存文件", self.default_save_path, "文本文件 (*.txt);;所有文件 (*)"
        )
        if file_path:
            self.default_save_path = file_path
            self.path_edit.setText(file_path)
    
    def generate_passwords(self):
        # 获取用户选择
        length = self.length_spin.value()
        count = self.count_spin.value()
        use_lower = self.lower_check.isChecked()
        use_upper = self.upper_check.isChecked()
        use_digits = self.digits_check.isChecked()
        use_special = self.special_check.isChecked()
        prefix = self.prefix_edit.text()
        suffix = self.suffix_edit.text()
        must_contain = self.contain_edit.text()
        
        # 验证至少选择了一种字符类型
        if not any([use_lower, use_upper, use_digits, use_special]):
            QMessageBox.warning(self, "错误", "请至少选择一种字符类型!")
            return
        
        # 验证密码长度是否足够包含前缀、后缀和至少一个随机字符
        required_length = len(prefix) + len(suffix) + 1
        if length < required_length:
            QMessageBox.warning(
                self, "错误", 
                f"密码长度至少需要 {required_length} 个字符才能包含指定的前缀和后缀!"
            )
            return
        
        # 禁用生成按钮，启用停止按钮
        self.generate_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        self.progress_bar.setVisible(True)
        self.progress_bar.setValue(0)
        
        # 清空当前列表
        self.password_list.clear()
        
        # 创建并启动生成线程
        self.generator_thread = PasswordGeneratorThread(
            length, count, use_lower, use_upper, use_digits, use_special,
            prefix, suffix, must_contain
        )
        self.generator_thread.progress_updated.connect(self.update_progress)
        self.generator_thread.passwords_generated.connect(self.display_passwords)
        self.generator_thread.finished.connect(self.generation_finished)
        self.generator_thread.start()
    
    def stop_generation(self):
        if self.generator_thread and self.generator_thread.isRunning():
            self.generator_thread.stop()
            self.generator_thread.wait()
            QMessageBox.information(self, "信息", "密码生成已停止")
    
    def update_progress(self, value):
        self.progress_bar.setValue(value)
    
    def display_passwords(self, passwords):
        self.password_list.clear()
        for password in passwords:
            item = QListWidgetItem(password)
            self.password_list.addItem(item)
    
    def generation_finished(self):
        self.generate_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)
        self.progress_bar.setVisible(False)
        self.generator_thread = None
    
    def get_selected_passwords(self):
        selected_items = self.password_list.selectedItems()
        return [item.text() for item in selected_items]
    
    def get_all_passwords(self):
        all_passwords = []
        for i in range(self.password_list.count()):
            all_passwords.append(self.password_list.item(i).text())
        return all_passwords
    
    def copy_selected_to_clipboard(self):
        passwords = self.get_selected_passwords()
        if passwords:
            clipboard = QApplication.clipboard()
            clipboard.setText('\n'.join(passwords))
            QMessageBox.information(self, "成功", f"已复制 {len(passwords)} 个密码到剪贴板!")
        else:
            QMessageBox.warning(self, "错误", "没有选中任何密码!")
    
    def copy_all_to_clipboard(self):
        passwords = self.get_all_passwords()
        if passwords:
            clipboard = QApplication.clipboard()
            clipboard.setText('\n'.join(passwords))
            QMessageBox.information(self, "成功", f"已复制所有 {len(passwords)} 个密码到剪贴板!")
        else:
            QMessageBox.warning(self, "错误", "没有密码可复制!")
    
    def save_selected_to_file(self):
        passwords = self.get_selected_passwords()
        if not passwords:
            QMessageBox.warning(self, "错误", "没有选中任何密码!")
            return
        
        try:
            # 检查文件是否已存在
            file_exists = os.path.exists(self.default_save_path)
            
            # 使用追加模式写入文件
            with open(self.default_save_path, 'a', encoding='utf-8') as f:
                # 如果文件已存在且有内容，添加分隔符
                if file_exists and os.path.getsize(self.default_save_path) > 0:
                    f.write('\n\n')
                f.write('\n'.join(passwords))
            QMessageBox.information(
                self, "成功", 
                f"已追加 {len(passwords)} 个密码到默认文件:\n{self.default_save_path}"
            )
        except Exception as e:
            QMessageBox.critical(self, "错误", f"保存文件时出错: {str(e)}")
    
    def save_all_to_file(self):
        passwords = self.get_all_passwords()
        if not passwords:
            QMessageBox.warning(self, "错误", "没有密码可保存!")
            return
        
        try:
            # 检查文件是否已存在
            file_exists = os.path.exists(self.default_save_path)
            
            # 使用追加模式写入文件
            with open(self.default_save_path, 'a', encoding='utf-8') as f:
                # 如果文件已存在且有内容，添加分隔符
                if file_exists and os.path.getsize(self.default_save_path) > 0:
                    f.write('\n\n')
                f.write('\n'.join(passwords))
            QMessageBox.information(
                self, "成功", 
                f"已追加所有 {len(passwords)} 个密码到默认文件:\n{self.default_save_path}"
            )
        except Exception as e:
            QMessageBox.critical(self, "错误", f"保存文件时出错: {str(e)}")
    
    def clear_results(self):
        self.password_list.clear()
    
    def closeEvent(self, event):
        if self.generator_thread and self.generator_thread.isRunning():
            self.generator_thread.stop()
            self.generator_thread.wait()
        event.accept()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = PasswordGeneratorApp()
    window.show()
    sys.exit(app.exec())